//+------------------------------------------------------------------+
//|                                           GoldTradePro_MQL5.mq5|
//|                   Copyright 2023, Wim Schrynemakers (Converted) |
//|                                        https://forexcracked.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Wim Schrynemakers (Converted)"
#property link      "https://forexcracked.com"
#property version   "1.0.1"
#property description "MQL5 版本 Gold Trade Pro EA."

#include <Trade/Trade.mqh>

//--- 输入参数
//--- 组: 通用设置
sinput group "通用设置";
input bool   ShowInfoPanel       = true;     // 显示信息面板
input double InfoPanelSizeAdjust = 1.0;      // 信息面板尺寸调整
input bool   UpdateInfoTesting   = false;    // 测试期间更新信息面板
input double MaxSpread           = 500;      // 最大允许点差 (以点为单位)
input bool   SetSLTPAfterEntry   = false;    // 入场后设置止损/止盈
input bool   VirtualExpiration   = true;     // 对挂单使用虚拟过期时间
input long   BaseMagicNumber     = 1000;     // 基础魔术数字
input string TradeComment        = "GoldTradePro_MQL5"; // 交易注释
input bool   DeleteOldest        = true;     // 挂单超限时删除最不可能成交的挂单

//--- 组: 手数设置
sinput group "手数设置";
// MQL4中使用枚举。为简单起见，我们暂时使用描述性注释。
// 风险计算: 0-手动手数, 1-按余额计算手数, 2-按风险百分比
input int    RiskCalculationMode = 0;        // 手数大小模式 (0:手动, 1:手数/余额, 2:风险%)
input double StartLots           = 0.01;     // 手动初始手数
input int    LotPerBalanceStep   = 600;      // 每余额步进的手数
input double ManualRiskPerTrade  = 2.0;      // 每笔交易最大风险 (%)
input bool   UseEquityForLots    = false;    // 使用净值而非余额计算手数
input bool   OnlyIncreaseLotSize = true;     // 只增加手数，永不减少

//--- 组: 策略开关
sinput group "策略开关";
input bool RunStrategyA = false; // 运行策略 A
input bool RunStrategyC = false; // 运行策略 C
input bool RunStrategyD = false; // 运行策略 D
input bool RunStrategyE = false; // 运行策略 E
input bool RunStrategyF = true; // 运行策略 F
input bool RunStrategyG = false; // 运行策略 G
input bool RunStrategyH = false; // 运行策略 H

//--- 组: 策略 A 设置
sinput group "策略 A 设置";
input ENUM_TIMEFRAMES StA_Timeframe               = PERIOD_M30;    // 信号时间周期
input int             StA_FractalsLeftBars        = 2;            // 分形左侧K线数
input int             StA_FractalsRightBars       = 4;            // 分形右侧K线数
input int             StA_SearchPeriod            = 160;          // 寻找分形信号的K线范围
input double          StA_StopLoss_Points         = 1300.0;       // 止损点数
input double          StA_TakeProfit_Points       = 1700.0;       // 止盈点数
input double          StA_BuyStop_Offset_Points   = -140.0;       // 买入挂单偏移点数
input double          StA_SellStop_Offset_Points  = -290.0;       // 卖出挂单偏移点数
input int             StA_Pending_Expiration_Hours= 408;          // 挂单有效小时
input int             StA_Max_Pending_Orders      = 1;            // 最大挂单数量

//--- 组: 策略 C 设置
sinput group "策略 C 设置";
input ENUM_TIMEFRAMES StC_Timeframe               = PERIOD_D1;    // 信号时间周期
input int             StC_FractalsLeftBars        = 3;            // 分形左侧K线数
input int             StC_FractalsRightBars       = 18;           // 分形右侧K线数
input int             StC_SearchPeriod            = 180;          // 寻找分形信号的K线范围
input double          StC_StopLoss_Points         = 1200.0;       // 止损点数
input double          StC_TakeProfit_Points       = 1800.0;       // 止盈点数
input double          StC_BuyStop_Offset_Points   = -130.0;       // 买入挂单偏移点数
input double          StC_SellStop_Offset_Points  = -30.0;        // 卖出挂单偏移点数
input int             StC_Pending_Expiration_Hours= 408;          // 挂单有效小时
input int             StC_Max_Pending_Orders      = 1;            // 最大挂单数量

//--- 组: 策略 D 设置
sinput group "策略 D 设置";
input ENUM_TIMEFRAMES StD_Timeframe               = PERIOD_D1;    // 信号时间周期
input int             StD_FractalsLeftBars        = 2;            // 分形左侧K线数
input int             StD_FractalsRightBars       = 4;            // 分形右侧K线数
input int             StD_SearchPeriod            = 240;          // 寻找分形信号的K线范围
input double          StD_StopLoss_Points         = 1300.0;       // 止损点数
input double          StD_TakeProfit_Points       = 1700.0;       // 止盈点数
input double          StD_BuyStop_Offset_Points   = -250.0;       // 买入挂单偏移点数
input double          StD_SellStop_Offset_Points  = -130.0;       // 卖出挂单偏移点数
input int             StD_Pending_Expiration_Hours= 48;           // 挂单有效小时
input int             StD_Max_Pending_Orders      = 1;            // 最大挂单数量

//--- 组: 策略 E 设置
sinput group "策略 E 设置";
input ENUM_TIMEFRAMES StE_Timeframe               = PERIOD_D1;    // 信号时间周期
input int             StE_FractalsLeftBars        = 3;            // 分形左侧K线数
input int             StE_FractalsRightBars       = 15;           // 分形右侧K线数
input int             StE_SearchPeriod            = 230;          // 寻找分形信号的K线范围
input double          StE_StopLoss_Points         = 600.0;        // 止损点数
input double          StE_TakeProfit_Points       = 1700.0;       // 止盈点数
input double          StE_BuyStop_Offset_Points   = -170.0;       // 买入挂单偏移点数
input double          StE_SellStop_Offset_Points  = -70.0;        // 卖出挂单偏移点数
input int             StE_Pending_Expiration_Hours= 480;          // 挂单有效小时
input int             StE_Max_Pending_Orders      = 1;            // 最大挂单数量

//--- 组: 策略 F 设置
sinput group "策略 F 设置";
input ENUM_TIMEFRAMES StF_Timeframe               = PERIOD_M30;    // 信号时间周期
input int             StF_FractalsLeftBars        = 2;            // 分形左侧K线数
input int             StF_FractalsRightBars       = 12;           // 分形右侧K线数
input int             StF_SearchPeriod            = 50;           // 寻找分形信号的K线范围
input double          StF_StopLoss_Points         = 1000.0;       // 止损点数
input double          StF_TakeProfit_Points       = 1900.0;       // 止盈点数
input double          StF_BuyStop_Offset_Points   = -1810.0;       // 买入挂单偏移点数
input double          StF_SellStop_Offset_Points  = -300.0;        // 卖出挂单偏移点数
input int             StF_Pending_Expiration_Hours= 384;          // 挂单有效小时
input int             StF_Max_BuyStop_Orders      = 1;            // 最大买单数量
input int             StF_Max_SellStop_Orders     = 1;            // 最大卖单数量

//--- 组: 策略 G 设置
sinput group "策略 G 设置";
input ENUM_TIMEFRAMES StG_Timeframe               = PERIOD_D1;    // 信号时间周期
input int             StG_FractalsLeftBars        = 2;            // 分形左侧K线数
input int             StG_FractalsRightBars       = 17;           // 分形右侧K线数
input int             StG_SearchPeriod            = 110;          // 寻找分形信号的K线范围
input double          StG_StopLoss_Points         = 1200.0;       // 止损点数
input double          StG_TakeProfit_Points       = 1600.0;       // 止盈点数
input double          StG_BuyStop_Offset_Points   = -40.0;        // 买入挂单偏移点数
input double          StG_SellStop_Offset_Points  = -140.0;       // 卖出挂单偏移点数
input int             StG_Pending_Expiration_Hours= 240;          // 挂单有效小时
input int             StG_Max_Pending_Orders      = 1;            // 最大挂单数量

//--- 组: 策略 H 设置
sinput group "策略 H 设置";
input ENUM_TIMEFRAMES StH_Timeframe               = PERIOD_D1;    // 信号时间周期
input int             StH_FractalsLeftBars        = 2;            // 分形左侧K线数
input int             StH_FractalsRightBars       = 7;            // 分形右侧K线数
input int             StH_SearchPeriod            = 20;           // 寻找分形信号的K线范围
input double          StH_StopLoss_Points         = 600.0;        // 止损点数
input double          StH_TakeProfit_Points       = 4900.0;       // 止盈点数
input double          StH_BuyStop_Offset_Points   = -130.0;       // 买入挂单偏移点数
input double          StH_SellStop_Offset_Points  = -120.0;       // 卖出挂单偏移点数
input int             StH_Pending_Expiration_Hours= 432;          // 挂单有效小时
input int             StH_Max_Pending_Orders      = 1;            // 最大挂单数量

//--- 组: 订单管理
sinput group "订单管理";
input bool   EnableTrailingStop            = true;   // 启用标准追踪止损
input double TrailingStopDistance_Points   = 500.0;  // 追踪止损距离 (点)
input double TrailingStopActivation_Points = 200.0;  // 追踪止损激活盈利点数 (点)
input bool   EnableBreakEven               = true;   // 启用盈亏平衡
input double BreakEvenActivation_Points    = 200.0;  // 盈亏平衡激活盈利点数 (点)
input double BreakEvenProfit_Points        = 10.0;   // 保本后锁定的最小盈利点数 (点)

//--- 组: 交易时间过滤器
sinput group "交易时间过滤器";
input bool   EnableTimeFilter  = true;     // 启用时间过滤器
input string Monday_Hours      = "0-23";   // 周一允许的小时范围 (格式: 0-23)
input string Tuesday_Hours     = "0-23";   // 周二允许的小时范围
input string Wednesday_Hours   = "0-23";   // 周三允许的小时范围
input string Thursday_Hours    = "0-23";   // 周四允许的小时范围
input string Friday_Hours      = "0-23";   // 周五允许的小时范围
input bool   EnableFridayExit  = true;     // 启用周五收盘
input int    FridayExit_Hour   = 22;       // 周五收盘开始小时

//--- 全局变量
CTrade   m_trade;
string   m_symbol;
int      m_digits;
double   m_point;

//--- 策略A的全局变量
int StA_FractalHandle = INVALID_HANDLE;
static datetime StA_LastSignalBarTime = 0;

//--- 策略C的全局变量
static datetime StC_LastSignalBarTime = 0;

//--- 策略D, E, F, G, H 的全局变量
static datetime StD_LastSignalBarTime = 0;
static datetime StE_LastSignalBarTime = 0;
static datetime StF_LastSignalBarTime = 0;
static datetime StG_LastSignalBarTime = 0;
static datetime StH_LastSignalBarTime = 0;

//--- 策略F的ATR指标句柄
int StF_ATRHandle = INVALID_HANDLE;

//--- 函数前向声明
void ExecuteStrategyA();
void ExecuteStrategyC();
void ExecuteStrategyD();
void ExecuteStrategyE();
void ExecuteStrategyF();
void ExecuteStrategyG();
void ExecuteStrategyH();
void ExecuteStrategies();
void ManageOpenTrades();
double GetFractalSignal(int direction, ENUM_TIMEFRAMES timeframe, int search_period, int left_bars, int right_bars);
void ManagePositions();
void ManagePendingOrders();
void ApplyBreakEven(ulong position_ticket);
void ApplyTrailingStop(ulong position_ticket);
void ManageExceededPendingOrders(long magic_number, int max_buy_orders, int max_sell_orders);
bool IsTradingAllowed();
bool IsInAllowedHours(int current_hour, string allowed_hours_range);
void CloseAllTradesAndOrders();

//+------------------------------------------------------------------+
//| EA初始化函数                                                    |
//+------------------------------------------------------------------+
int OnInit()
{
    //--- 初始化交易对象
    m_trade.SetExpertMagicNumber(BaseMagicNumber);
    m_trade.SetMarginMode(); // 使用交易品种的默认保证金模式
    m_trade.SetTypeFillingBySymbol(Symbol());

    //--- 获取交易品种属性
    m_symbol = Symbol();
    m_digits = (int)SymbolInfoInteger(m_symbol, SYMBOL_DIGITS);
    m_point = SymbolInfoDouble(m_symbol, SYMBOL_POINT);

    //--- 初始化策略A的指标
    StA_FractalHandle = iFractals(m_symbol, StA_Timeframe);
    if(StA_FractalHandle == INVALID_HANDLE)
    {
        Print("错误: 无法创建策略A的分形指标句柄。错误代码: ", GetLastError());
        return(INIT_FAILED);
    }

    //--- 初始化策略F的ATR指标
    StF_ATRHandle = iATR(m_symbol, StF_Timeframe, 14);
    if(StF_ATRHandle == INVALID_HANDLE)
    {
        Print("错误: 无法创建策略F的ATR指标句柄。错误代码: ", GetLastError());
        return(INIT_FAILED);
    }

    Print("EA已初始化: ", TradeComment);
    Print("交易品种: ", m_symbol, ", 小数位数: ", m_digits, ", 点值: ", m_point);
    Print("魔术数字: ", BaseMagicNumber);
    
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| EA去初始化函数                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    //--- 释放指标句柄
    if(StA_FractalHandle != INVALID_HANDLE)
    {
        IndicatorRelease(StA_FractalHandle);
    }
    
    if(StF_ATRHandle != INVALID_HANDLE)
    {
        IndicatorRelease(StF_ATRHandle);
    }
    
    Print("EA已去初始化。原因代码: ", reason);
}

//+------------------------------------------------------------------+
//| EA OnTick函数                                                    |
//+------------------------------------------------------------------+
void OnTick()
{
    //--- 检查是否允许交易
    if(!IsTradingAllowed())
    {
       // 如果返回 false，可能是因为周末平仓逻辑已执行，直接返回即可
       return;
    }

    //--- 主要逻辑执行
    ExecuteStrategies();
    
    //--- 管理已开仓位 (例如追踪止损)
    ManageOpenTrades();
}

//+------------------------------------------------------------------+
//| 根据输入设置执行交易策略                                         |
//+------------------------------------------------------------------+
void ExecuteStrategies()
{
    //--- 此函数将调用各个独立的策略函数
    if(RunStrategyA) ExecuteStrategyA();
    if(RunStrategyC) ExecuteStrategyC();
    if(RunStrategyD) ExecuteStrategyD();
    if(RunStrategyE) ExecuteStrategyE();
    if(RunStrategyF) ExecuteStrategyF();
    if(RunStrategyG) ExecuteStrategyG();
    if(RunStrategyH) ExecuteStrategyH();
}

//+------------------------------------------------------------------+
//| 管理此EA所有已开仓位                                             |
//+------------------------------------------------------------------+
void ManageOpenTrades()
{
    //--- 分别管理市场持仓和挂单
    ManagePositions();
    ManagePendingOrders();
}

//+------------------------------------------------------------------+
//| 管理所有市场持仓 (追踪止损, 盈亏平衡等)                          |
//+------------------------------------------------------------------+
void ManagePositions()
{
    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
        ulong ticket = PositionGetTicket(i);
        if(ticket > 0)
        {
            // 筛选属于本EA且是当前交易品种的持仓
            if(PositionGetInteger(POSITION_MAGIC) >= BaseMagicNumber && PositionGetInteger(POSITION_MAGIC) <= BaseMagicNumber + 8
               && PositionGetString(POSITION_SYMBOL) == m_symbol)
            {
                if(EnableBreakEven)
                {
                    ApplyBreakEven(ticket);
                }
                if(EnableTrailingStop)
                {
                    ApplyTrailingStop(ticket);
                }
            }
        }
    }
}

//+------------------------------------------------------------------+
//| 管理所有挂单 (处理虚拟过期)                                      |
//+------------------------------------------------------------------+
void ManagePendingOrders()
{
    if(!VirtualExpiration) return; // 如果不使用虚拟过期，则直接返回

    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        ulong ticket = OrderGetTicket(i);
        if(ticket > 0)
        {
            long magic = OrderGetInteger(ORDER_MAGIC);
            // 筛选属于本EA策略且是当前品种的挂单
            if(magic >= BaseMagicNumber + 1 && magic <= BaseMagicNumber + 8
               && OrderGetString(ORDER_SYMBOL) == m_symbol)
            {
                long order_type = OrderGetInteger(ORDER_TYPE);
                if(order_type == ORDER_TYPE_BUY_STOP || order_type == ORDER_TYPE_SELL_STOP)
                {
                    int expiration_hours = 0;
                    // 根据魔术数字确定该挂单属于哪个策略，并获取其过期时间
                    switch((int)(magic - BaseMagicNumber))
                    {
                        case 1: expiration_hours = StA_Pending_Expiration_Hours; break;
                        case 3: expiration_hours = StC_Pending_Expiration_Hours; break; // 策略B被跳过，所以是+3
                        case 4: expiration_hours = StD_Pending_Expiration_Hours; break;
                        case 5: expiration_hours = StE_Pending_Expiration_Hours; break;
                        case 6: expiration_hours = StF_Pending_Expiration_Hours; break;
                        case 7: expiration_hours = StG_Pending_Expiration_Hours; break;
                        case 8: expiration_hours = StH_Pending_Expiration_Hours; break;
                    }

                    if(expiration_hours > 0)
                    {
                        datetime setup_time = (datetime)OrderGetInteger(ORDER_TIME_SETUP);
                        if(TimeCurrent() > setup_time + expiration_hours * 3600)
                        {
                            m_trade.OrderDelete(ticket);
                        }
                    }
                }
            }
        }
    }
}


//+------------------------------------------------------------------+
//| 对指定持仓应用盈亏平衡逻辑                                       |
//+------------------------------------------------------------------+
void ApplyBreakEven(ulong position_ticket)
{
    if(!PositionSelectByTicket(position_ticket)) return;

    double open_price = PositionGetDouble(POSITION_PRICE_OPEN);
    double current_sl = PositionGetDouble(POSITION_SL);
    double current_price = PositionGetDouble(POSITION_PRICE_CURRENT);
    ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

    double new_sl = 0;
    bool modify = false;

    if(type == POSITION_TYPE_BUY)
    {
        // 计算盈利点数
        if((current_price - open_price) > BreakEvenActivation_Points * m_point)
        {
            new_sl = NormalizeDouble(open_price + BreakEvenProfit_Points * m_point, m_digits);
            // 只有当新的止损位优于（高于）当前止损位时才修改
            if(current_sl < new_sl)
            {
                modify = true;
            }
        }
    }
    else if(type == POSITION_TYPE_SELL)
    {
        // 计算盈利点数
        if((open_price - current_price) > BreakEvenActivation_Points * m_point)
        {
            new_sl = NormalizeDouble(open_price - BreakEvenProfit_Points * m_point, m_digits);
            // 只有当新的止损位优于（低于）当前止损位时才修改 (对于空单, 0被认为是无止损)
            if(current_sl > new_sl || current_sl == 0)
            {
                modify = true;
            }
        }
    }

    if(modify)
    {
        m_trade.PositionModify(position_ticket, new_sl, PositionGetDouble(POSITION_TP));
    }
}

//+------------------------------------------------------------------+
//| 对指定持仓应用追踪止损逻辑                                       |
//+------------------------------------------------------------------+
void ApplyTrailingStop(ulong position_ticket)
{
    if(!PositionSelectByTicket(position_ticket)) return;

    double open_price = PositionGetDouble(POSITION_PRICE_OPEN);
    double current_sl = PositionGetDouble(POSITION_SL);
    double current_price = PositionGetDouble(POSITION_PRICE_CURRENT);
    ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

    double new_sl = 0;
    bool modify = false;

    if(type == POSITION_TYPE_BUY)
    {
        if((current_price - open_price) > TrailingStopActivation_Points * m_point)
        {
            new_sl = NormalizeDouble(current_price - TrailingStopDistance_Points * m_point, m_digits);
            if(current_sl < new_sl)
            {
                modify = true;
            }
        }
    }
    else if(type == POSITION_TYPE_SELL)
    {
        if((open_price - current_price) > TrailingStopActivation_Points * m_point)
        {
            new_sl = NormalizeDouble(current_price + TrailingStopDistance_Points * m_point, m_digits);
            if(current_sl > new_sl || current_sl == 0)
            {
                modify = true;
            }
        }
    }

    if(modify)
    {
        m_trade.PositionModify(position_ticket, new_sl, PositionGetDouble(POSITION_TP));
    }
}

//+------------------------------------------------------------------+
//| 查找分形信号                                                     |
//| direction: 1表示向上分形(买入), -1表示向下分形(卖出)             |
//+------------------------------------------------------------------+
double GetFractalSignal(int direction, ENUM_TIMEFRAMES timeframe, int search_period, int left_bars, int right_bars)
{
    MqlRates rates[];
    // 获取足够的数据，需要覆盖搜索范围和分形的左右臂
    int rates_to_copy = search_period + MathMax(left_bars, right_bars);
    if(CopyRates(m_symbol, timeframe, 0, rates_to_copy, rates) != rates_to_copy)
    {
        return 0.0;
    }
    // 将数组设置为时间序列，rates[0]是当前最新的K线
    ArraySetAsSeries(rates, true);

    // 从最近的完整K线开始 (index 1) 向历史搜索
    // 循环的终点要确保有足够的左侧K线用于比较
    for(int i = 1; i < search_period; i++)
    {
        bool is_fractal = true;
        if(direction == 1) // 寻找向上分形 (高点)
        {
            double central_high = rates[i].high;
            // 检查左侧
            for(int j = 1; j <= left_bars; j++)
            {
                if(i + j >= rates_to_copy || rates[i + j].high >= central_high)
                {
                    is_fractal = false;
                    break;
                }
            }
            if(!is_fractal) continue;

            // 检查右侧
            for(int j = 1; j <= right_bars; j++)
            {
                 if(i - j < 0 || rates[i - j].high > central_high)
                {
                    is_fractal = false;
                    break;
                }
            }
        }
        else // 寻找向下分形 (低点)
        {
            double central_low = rates[i].low;
            // 检查左侧
            for(int j = 1; j <= left_bars; j++)
            {
                if(i + j >= rates_to_copy || rates[i + j].low <= central_low)
                {
                    is_fractal = false;
                    break;
                }
            }
            if(!is_fractal) continue;

            // 检查右侧
            for(int j = 1; j <= right_bars; j++)
            {
                if(i - j < 0 || rates[i - j].low < central_low)
                {
                    is_fractal = false;
                    break;
                }
            }
        }

        if(is_fractal)
        {
            return (direction == 1) ? rates[i].high : rates[i].low;
        }
    }
    return 0.0;
}

//+------------------------------------------------------------------+
//| 管理超额的挂单 (当挂单数>最大限额时删除最不可能成交的订单)       |
//+------------------------------------------------------------------+
void ManageExceededPendingOrders(long magic_number, int max_buy_orders, int max_sell_orders)
{
    int buy_stop_count = 0;
    int sell_stop_count = 0;
    
    ulong worst_buy_stop_ticket = 0;
    double worst_buy_stop_price = 0; // 最高价的买单是"最差"的，最不可能成交

    ulong worst_sell_stop_ticket = 0;
    double worst_sell_stop_price = 999999.0; // 最低价的卖单是"最差"的

    //--- 遍历所有挂单
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        ulong ticket = OrderGetTicket(i);
        if(ticket > 0 && OrderGetInteger(ORDER_MAGIC) == magic_number && OrderGetString(ORDER_SYMBOL) == m_symbol)
        {
            ENUM_ORDER_TYPE order_type = (ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE);
            double open_price = OrderGetDouble(ORDER_PRICE_OPEN);

            if(order_type == ORDER_TYPE_BUY_STOP)
            {
                buy_stop_count++;
                if(open_price > worst_buy_stop_price)
                {
                    worst_buy_stop_price = open_price;
                    worst_buy_stop_ticket = ticket;
                }
            }
            else if(order_type == ORDER_TYPE_SELL_STOP)
            {
                sell_stop_count++;
                if(open_price < worst_sell_stop_price)
                {
                    worst_sell_stop_price = open_price;
                    worst_sell_stop_ticket = ticket;
                }
            }
        }
    }

    //--- 如果买入挂单超过限制，删除最差的一个
    if(buy_stop_count > max_buy_orders && worst_buy_stop_ticket > 0)
    {
        m_trade.OrderDelete(worst_buy_stop_ticket);
    }
    
    //--- 如果卖出挂单超过限制，删除最差的一个
    if(sell_stop_count > max_sell_orders && worst_sell_stop_ticket > 0)
    {
        m_trade.OrderDelete(worst_sell_stop_ticket);
    }
}


//+------------------------------------------------------------------+
//| 检查当前是否在允许的交易时间内                                   |
//+------------------------------------------------------------------+
bool IsTradingAllowed()
{
    if(!EnableTimeFilter)
    {
        return true; // 如果过滤器未启用，则始终允许交易
    }

    MqlDateTime dt;
    TimeCurrent(dt); // 使用服务器时间

    int day_of_week = dt.day_of_week; // 0-周日, 1-周一, ..., 6-周六
    int hour = dt.hour;
    
    // 周末平仓逻辑
    if(EnableFridayExit && day_of_week == FRIDAY && hour >= FridayExit_Hour)
    {
        CloseAllTradesAndOrders();
        return false; // 停止本周所有交易活动
    }
    
    // 周六和周日不交易
    if(day_of_week == SATURDAY || day_of_week == SUNDAY)
    {
        return false;
    }

    // 按天检查交易时间
    switch(day_of_week)
    {
        case MONDAY:    return IsInAllowedHours(hour, Monday_Hours);
        case TUESDAY:   return IsInAllowedHours(hour, Tuesday_Hours);
        case WEDNESDAY: return IsInAllowedHours(hour, Wednesday_Hours);
        case THURSDAY:  return IsInAllowedHours(hour, Thursday_Hours);
        case FRIDAY:    return IsInAllowedHours(hour, Friday_Hours);
        default:        return false;
    }
}

//+------------------------------------------------------------------+
//| 检查当前小时是否在给定的字符串时间范围内                         |
//+------------------------------------------------------------------+
bool IsInAllowedHours(int current_hour, string allowed_hours_range)
{
    string parts[];
    if(StringSplit(allowed_hours_range, '-', parts) != 2)
    {
        Print("时间范围格式错误: ", allowed_hours_range, ". 请使用 '开始小时-结束小时' 格式, 例如 '2-18'.");
        return false;
    }
    
    int start_hour = (int)StringToInteger(parts[0]);
    int end_hour = (int)StringToInteger(parts[1]);

    // 检查是否为正常顺序 (例如 2-18)
    if(start_hour <= end_hour)
    {
        return (current_hour >= start_hour && current_hour <= end_hour);
    }
    // 检查是否为跨夜顺序 (例如 22-04)
    else
    {
        return (current_hour >= start_hour || current_hour <= end_hour);
    }
}

//+------------------------------------------------------------------+
//| 关闭所有由本EA开启的持仓和挂单                                   |
//+------------------------------------------------------------------+
void CloseAllTradesAndOrders()
{
    //--- 关闭所有市场持仓
    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
        ulong ticket = PositionGetTicket(i);
        if(ticket > 0 && PositionGetString(POSITION_SYMBOL) == m_symbol)
        {
            long magic = PositionGetInteger(POSITION_MAGIC);
            if(magic >= BaseMagicNumber && magic <= BaseMagicNumber + 8)
            {
                m_trade.PositionClose(ticket);
            }
        }
    }

    //--- 删除所有挂单
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        ulong ticket = OrderGetTicket(i);
        if(ticket > 0 && OrderGetString(ORDER_SYMBOL) == m_symbol)
        {
            long magic = OrderGetInteger(ORDER_MAGIC);
            if(magic >= BaseMagicNumber && magic <= BaseMagicNumber + 8)
            {
                m_trade.OrderDelete(ticket);
            }
        }
    }
}


//+------------------------------------------------------------------+
//| 策略 A 执行逻辑                                                  |
//+------------------------------------------------------------------+
void ExecuteStrategyA()
{
    //--- 如果挂单超出限制，删除最不可能成交的挂单
    if(DeleteOldest)
    {
        ManageExceededPendingOrders(BaseMagicNumber + 1, StA_Max_Pending_Orders, StA_Max_Pending_Orders);
    }

    //--- 检查是否允许交易（双重检查）
    if(!IsTradingAllowed()) return;
    
    //--- 检查是否有新的K线生成，避免在同一根K线上重复操作
    MqlRates rates[];
    if(CopyRates(m_symbol, StA_Timeframe, 0, 1, rates) < 1) return;
    if(rates[0].time == StA_LastSignalBarTime) return;
    StA_LastSignalBarTime = rates[0].time;
    
    //--- 检查当前策略的挂单数量
    int pending_orders_count = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        ulong ticket = OrderGetTicket(i);
        if(OrderGetInteger(ORDER_MAGIC) == BaseMagicNumber + 1 && OrderGetString(ORDER_SYMBOL) == m_symbol)
        {
            if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP || OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP)
            {
                pending_orders_count++;
            }
        }
    }
    
    if(pending_orders_count >= StA_Max_Pending_Orders)
    {
        return; // 已达到最大挂单数
    }

    //--- 获取信号
    double buy_signal_price = GetFractalSignal(1, StA_Timeframe, StA_SearchPeriod, StA_FractalsLeftBars, StA_FractalsRightBars);
    double sell_signal_price = GetFractalSignal(-1, StA_Timeframe, StA_SearchPeriod, StA_FractalsLeftBars, StA_FractalsRightBars);
    
    //--- 处理买入挂单
    if(buy_signal_price > 0)
    {
        double stop_price = NormalizeDouble(buy_signal_price + StA_BuyStop_Offset_Points * m_point, m_digits);
        double sl = NormalizeDouble(stop_price - StA_StopLoss_Points * m_point, m_digits);
        double tp = NormalizeDouble(stop_price + StA_TakeProfit_Points * m_point, m_digits);
        datetime expiration = TimeCurrent() + (StA_Pending_Expiration_Hours * 3600);
        
        if(stop_price > SymbolInfoDouble(m_symbol, SYMBOL_ASK))
        {
            // 临时设置策略A的魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber + 1);
            m_trade.BuyStop(StartLots, stop_price, m_symbol, sl, tp, ORDER_TIME_SPECIFIED, expiration, TradeComment + "_A");
            // 恢复基础魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber);
        }
    }
    
    //--- 处理卖出挂单
    if(sell_signal_price > 0)
    {
        double stop_price = NormalizeDouble(sell_signal_price + StA_SellStop_Offset_Points * m_point, m_digits);
        double sl = NormalizeDouble(stop_price + StA_StopLoss_Points * m_point, m_digits);
        double tp = NormalizeDouble(stop_price - StA_TakeProfit_Points * m_point, m_digits);
        datetime expiration = TimeCurrent() + (StA_Pending_Expiration_Hours * 3600);
        
        if(stop_price < SymbolInfoDouble(m_symbol, SYMBOL_BID))
        {
            // 临时设置策略A的魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber + 1);
            m_trade.SellStop(StartLots, stop_price, m_symbol, sl, tp, ORDER_TIME_SPECIFIED, expiration, TradeComment + "_A");
            // 恢复基础魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber);
        }
    }
}

//+------------------------------------------------------------------+
//| 策略 C 执行逻辑                                                  |
//+------------------------------------------------------------------+
void ExecuteStrategyC()
{
    //--- 如果挂单超出限制，删除最不可能成交的挂单
    if(DeleteOldest)
    {
        ManageExceededPendingOrders(BaseMagicNumber + 3, StC_Max_Pending_Orders, StC_Max_Pending_Orders);
    }

    //--- 检查是否允许交易
    if(!IsTradingAllowed()) return;

    //--- 检查是否有新的K线生成，避免在同一根K线上重复操作
    MqlRates rates[];
    if(CopyRates(m_symbol, StC_Timeframe, 0, 1, rates) < 1) return;
    if(rates[0].time == StC_LastSignalBarTime) return;
    StC_LastSignalBarTime = rates[0].time;
    
    //--- 检查当前策略的挂单数量
    int pending_orders_count = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        ulong ticket = OrderGetTicket(i);
        if(OrderGetInteger(ORDER_MAGIC) == BaseMagicNumber + 3 && OrderGetString(ORDER_SYMBOL) == m_symbol)
        {
            if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP || OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP)
            {
                pending_orders_count++;
            }
        }
    }
    
    if(pending_orders_count >= StC_Max_Pending_Orders)
    {
        return; // 已达到最大挂单数
    }

    //--- 获取信号
    double buy_signal_price = GetFractalSignal(1, StC_Timeframe, StC_SearchPeriod, StC_FractalsLeftBars, StC_FractalsRightBars);
    double sell_signal_price = GetFractalSignal(-1, StC_Timeframe, StC_SearchPeriod, StC_FractalsLeftBars, StC_FractalsRightBars);
    
    //--- 处理买入挂单
    if(buy_signal_price > 0)
    {
        double stop_price = NormalizeDouble(buy_signal_price + StC_BuyStop_Offset_Points * m_point, m_digits);
        double sl = NormalizeDouble(stop_price - StC_StopLoss_Points * m_point, m_digits);
        double tp = NormalizeDouble(stop_price + StC_TakeProfit_Points * m_point, m_digits);
        datetime expiration = TimeCurrent() + (StC_Pending_Expiration_Hours * 3600);
        
        if(stop_price > SymbolInfoDouble(m_symbol, SYMBOL_ASK))
        {
            // 临时设置策略C的魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber + 3);
            m_trade.BuyStop(StartLots, stop_price, m_symbol, sl, tp, ORDER_TIME_SPECIFIED, expiration, TradeComment + "_C");
            // 恢复基础魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber);
        }
    }
    
    //--- 处理卖出挂单
    if(sell_signal_price > 0)
    {
        double stop_price = NormalizeDouble(sell_signal_price + StC_SellStop_Offset_Points * m_point, m_digits);
        double sl = NormalizeDouble(stop_price + StC_StopLoss_Points * m_point, m_digits);
        double tp = NormalizeDouble(stop_price - StC_TakeProfit_Points * m_point, m_digits);
        datetime expiration = TimeCurrent() + (StC_Pending_Expiration_Hours * 3600);
        
        if(stop_price < SymbolInfoDouble(m_symbol, SYMBOL_BID))
        {
            // 临时设置策略C的魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber + 3);
            m_trade.SellStop(StartLots, stop_price, m_symbol, sl, tp, ORDER_TIME_SPECIFIED, expiration, TradeComment + "_C");
            // 恢复基础魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber);
        }
    }
}

//+------------------------------------------------------------------+
//| 策略 D 执行逻辑                                                  |
//+------------------------------------------------------------------+
void ExecuteStrategyD()
{
    //--- 如果挂单超出限制，删除最不可能成交的挂单
    if(DeleteOldest)
    {
        ManageExceededPendingOrders(BaseMagicNumber + 4, StD_Max_Pending_Orders, StD_Max_Pending_Orders);
    }

    //--- 检查是否允许交易
    if(!IsTradingAllowed()) return;

    //--- 检查是否有新的K线生成，避免在同一根K线上重复操作
    MqlRates rates[];
    if(CopyRates(m_symbol, StD_Timeframe, 0, 1, rates) < 1) return;
    if(rates[0].time == StD_LastSignalBarTime) return;
    StD_LastSignalBarTime = rates[0].time;

    //--- 检查当前策略的挂单数量
    int pending_orders_count = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderGetTicket(i) > 0)
        {
            if(OrderGetInteger(ORDER_MAGIC) == BaseMagicNumber + 4 && OrderGetString(ORDER_SYMBOL) == m_symbol)
            {
                if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP || OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP)
                {
                    pending_orders_count++;
                }
            }
        }
    }

    if(pending_orders_count >= StD_Max_Pending_Orders)
    {
        return; // 已达到最大挂单数
    }

    //--- 获取信号
    double buy_signal_price = GetFractalSignal(1, StD_Timeframe, StD_SearchPeriod, StD_FractalsLeftBars, StD_FractalsRightBars);
    double sell_signal_price = GetFractalSignal(-1, StD_Timeframe, StD_SearchPeriod, StD_FractalsLeftBars, StD_FractalsRightBars);

    //--- 处理买入挂单
    if(buy_signal_price > 0)
    {
        double stop_price = NormalizeDouble(buy_signal_price + StD_BuyStop_Offset_Points * m_point, m_digits);
        double sl = NormalizeDouble(stop_price - StD_StopLoss_Points * m_point, m_digits);
        double tp = NormalizeDouble(stop_price + StD_TakeProfit_Points * m_point, m_digits);
        datetime expiration = TimeCurrent() + (StD_Pending_Expiration_Hours * 3600);

        if(stop_price > SymbolInfoDouble(m_symbol, SYMBOL_ASK))
        {
            // 临时设置策略D的魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber + 4);
            m_trade.BuyStop(StartLots, stop_price, m_symbol, sl, tp, ORDER_TIME_SPECIFIED, expiration, TradeComment + "_D");
            // 恢复基础魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber);
        }
    }

    //--- 处理卖出挂单
    if(sell_signal_price > 0)
    {
        double stop_price = NormalizeDouble(sell_signal_price + StD_SellStop_Offset_Points * m_point, m_digits);
        double sl = NormalizeDouble(stop_price + StD_StopLoss_Points * m_point, m_digits);
        double tp = NormalizeDouble(stop_price - StD_TakeProfit_Points * m_point, m_digits);
        datetime expiration = TimeCurrent() + (StD_Pending_Expiration_Hours * 3600);

        if(stop_price < SymbolInfoDouble(m_symbol, SYMBOL_BID))
        {
            // 临时设置策略D的魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber + 4);
            m_trade.SellStop(StartLots, stop_price, m_symbol, sl, tp, ORDER_TIME_SPECIFIED, expiration, TradeComment + "_D");
            // 恢复基础魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber);
        }
    }
}

//+------------------------------------------------------------------+
//| 策略 E 执行逻辑                                                  |
//+------------------------------------------------------------------+
void ExecuteStrategyE()
{
    //--- 如果挂单超出限制，删除最不可能成交的挂单
    if(DeleteOldest)
    {
        ManageExceededPendingOrders(BaseMagicNumber + 5, StE_Max_Pending_Orders, StE_Max_Pending_Orders);
    }

    //--- 检查是否允许交易
    if(!IsTradingAllowed()) return;

    //--- 检查是否有新的K线生成，避免在同一根K线上重复操作
    MqlRates rates[];
    if(CopyRates(m_symbol, StE_Timeframe, 0, 1, rates) < 1) return;
    if(rates[0].time == StE_LastSignalBarTime) return;
    StE_LastSignalBarTime = rates[0].time;

    //--- 检查当前策略的挂单数量
    int pending_orders_count = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderGetTicket(i) > 0)
        {
            if(OrderGetInteger(ORDER_MAGIC) == BaseMagicNumber + 5 && OrderGetString(ORDER_SYMBOL) == m_symbol)
            {
                if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP || OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP)
                {
                    pending_orders_count++;
                }
            }
        }
    }

    if(pending_orders_count >= StE_Max_Pending_Orders)
    {
        return; // 已达到最大挂单数
    }

    //--- 获取信号
    double buy_signal_price = GetFractalSignal(1, StE_Timeframe, StE_SearchPeriod, StE_FractalsLeftBars, StE_FractalsRightBars);
    double sell_signal_price = GetFractalSignal(-1, StE_Timeframe, StE_SearchPeriod, StE_FractalsLeftBars, StE_FractalsRightBars);

    //--- 处理买入挂单
    if(buy_signal_price > 0)
    {
        double stop_price = NormalizeDouble(buy_signal_price + StE_BuyStop_Offset_Points * m_point, m_digits);
        double sl = NormalizeDouble(stop_price - StE_StopLoss_Points * m_point, m_digits);
        double tp = NormalizeDouble(stop_price + StE_TakeProfit_Points * m_point, m_digits);
        datetime expiration = TimeCurrent() + (StE_Pending_Expiration_Hours * 3600);

        if(stop_price > SymbolInfoDouble(m_symbol, SYMBOL_ASK))
        {
            // 临时设置策略E的魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber + 5);
            m_trade.BuyStop(StartLots, stop_price, m_symbol, sl, tp, ORDER_TIME_SPECIFIED, expiration, TradeComment + "_E");
            // 恢复基础魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber);
        }
    }

    //--- 处理卖出挂单
    if(sell_signal_price > 0)
    {
        double stop_price = NormalizeDouble(sell_signal_price + StE_SellStop_Offset_Points * m_point, m_digits);
        double sl = NormalizeDouble(stop_price + StE_StopLoss_Points * m_point, m_digits);
        double tp = NormalizeDouble(stop_price - StE_TakeProfit_Points * m_point, m_digits);
        datetime expiration = TimeCurrent() + (StE_Pending_Expiration_Hours * 3600);

        if(stop_price < SymbolInfoDouble(m_symbol, SYMBOL_BID))
        {
            // 临时设置策略E的魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber + 5);
            m_trade.SellStop(StartLots, stop_price, m_symbol, sl, tp, ORDER_TIME_SPECIFIED, expiration, TradeComment + "_E");
            // 恢复基础魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber);
        }
    }
}

//+------------------------------------------------------------------+
//| 策略 F 执行逻辑                                                  |
//+------------------------------------------------------------------+
void ExecuteStrategyF()
{
    //--- 如果挂单超出限制，删除最不可能成交的挂单
    if(DeleteOldest)
    {
        ManageExceededPendingOrders(BaseMagicNumber + 6, StF_Max_BuyStop_Orders, StF_Max_SellStop_Orders);
    }

    //--- 检查是否允许交易
    if(!IsTradingAllowed()) return;

    //--- 检查是否有新的K线生成，避免在同一根K线上重复操作
    MqlRates rates[];
    if(CopyRates(m_symbol, StF_Timeframe, 0, 1, rates) < 1) return;
    if(rates[0].time == StF_LastSignalBarTime) return;
    StF_LastSignalBarTime = rates[0].time;

    //--- 检查当前策略的挂单数量
    int buy_stop_count = 0;
    int sell_stop_count = 0;
    
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        ulong ticket = OrderGetTicket(i);
        if(ticket > 0)
        {
            long order_magic = OrderGetInteger(ORDER_MAGIC);
            string order_symbol = OrderGetString(ORDER_SYMBOL);
            ENUM_ORDER_TYPE order_type = (ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE);
            
            if(order_magic == BaseMagicNumber + 6 && order_symbol == m_symbol)
            {
                if(order_type == ORDER_TYPE_BUY_STOP)
                {
                    buy_stop_count++;
                }
                else if(order_type == ORDER_TYPE_SELL_STOP)
                {
                    sell_stop_count++;
                }
            }
        }
    }

    //--- 获取ATR值用于动态止盈止损计算
    double atr_value = 0.0;
    double atr_buffer[];
    if(CopyBuffer(StF_ATRHandle, 0, 0, 1, atr_buffer) > 0)
    {
        atr_value = atr_buffer[0];
    }
    
    // 如果无法获取ATR值，使用默认值
    if(atr_value <= 0) atr_value = 100.0; // 默认ATR值

    //--- 获取信号
    double buy_signal_price = GetFractalSignal(1, StF_Timeframe, StF_SearchPeriod, StF_FractalsLeftBars, StF_FractalsRightBars);
    double sell_signal_price = GetFractalSignal(-1, StF_Timeframe, StF_SearchPeriod, StF_FractalsLeftBars, StF_FractalsRightBars);

    //--- 处理买入挂单
    if(buy_signal_price > 0 && buy_stop_count < StF_Max_BuyStop_Orders)
    {
        double stop_price = NormalizeDouble(buy_signal_price + StF_BuyStop_Offset_Points * m_point, m_digits);
        
        // 使用动态止盈止损：点数/1000 * ATR(14)
        double dynamic_sl_points = StF_StopLoss_Points  * atr_value;
        double dynamic_tp_points = StF_TakeProfit_Points  * atr_value;
        
        double sl = NormalizeDouble(stop_price - dynamic_sl_points * m_point, m_digits);
        double tp = NormalizeDouble(stop_price + dynamic_tp_points * m_point, m_digits);
        datetime expiration = TimeCurrent() + (StF_Pending_Expiration_Hours * 3600);
        double current_ask = SymbolInfoDouble(m_symbol, SYMBOL_ASK);

        if(stop_price > current_ask)
        {
            // 临时设置策略F的魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber + 6);
            bool result = m_trade.BuyStop(StartLots, stop_price, m_symbol, sl, tp, ORDER_TIME_SPECIFIED, expiration, TradeComment + "_F");
            // 恢复基础魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber);
        }
    }

    //--- 处理卖出挂单
    if(sell_signal_price > 0 && sell_stop_count < StF_Max_SellStop_Orders)
    {
        double stop_price = NormalizeDouble(sell_signal_price + StF_SellStop_Offset_Points * m_point, m_digits);
        
        // 使用动态止盈止损：点数/1000 * ATR(14)
        double dynamic_sl_points_sell = StF_StopLoss_Points  * atr_value;
        double dynamic_tp_points_sell = StF_TakeProfit_Points * atr_value;
        
        double sl = NormalizeDouble(stop_price + dynamic_sl_points_sell * m_point, m_digits);
        double tp = NormalizeDouble(stop_price - dynamic_tp_points_sell * m_point, m_digits);
        datetime expiration = TimeCurrent() + (StF_Pending_Expiration_Hours * 3600);
        double current_bid = SymbolInfoDouble(m_symbol, SYMBOL_BID);

        if(stop_price < current_bid)
        {
            // 临时设置策略F的魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber + 6);
            bool result = m_trade.SellStop(StartLots, stop_price, m_symbol, sl, tp, ORDER_TIME_SPECIFIED, expiration, TradeComment + "_F");
            // 恢复基础魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber);
        }
    }
}

//+------------------------------------------------------------------+
//| 策略 G 执行逻辑                                                  |
//+------------------------------------------------------------------+
void ExecuteStrategyG()
{
    //--- 如果挂单超出限制，删除最不可能成交的挂单
    if(DeleteOldest)
    {
        ManageExceededPendingOrders(BaseMagicNumber + 7, StG_Max_Pending_Orders, StG_Max_Pending_Orders);
    }
    
    //--- 检查是否允许交易
    if(!IsTradingAllowed()) return;
    
    //--- 检查是否有新的K线生成，避免在同一根K线上重复操作
    MqlRates rates[];
    if(CopyRates(m_symbol, StG_Timeframe, 0, 1, rates) < 1) return;
    if(rates[0].time == StG_LastSignalBarTime) return;
    StG_LastSignalBarTime = rates[0].time;

    //--- 检查当前策略的挂单数量
    int pending_orders_count = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderGetTicket(i) > 0)
        {
            if(OrderGetInteger(ORDER_MAGIC) == BaseMagicNumber + 7 && OrderGetString(ORDER_SYMBOL) == m_symbol)
            {
                if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP || OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP)
                {
                    pending_orders_count++;
                }
            }
        }
    }

    if(pending_orders_count >= StG_Max_Pending_Orders)
    {
        return; // 已达到最大挂单数
    }

    //--- 获取信号
    double buy_signal_price = GetFractalSignal(1, StG_Timeframe, StG_SearchPeriod, StG_FractalsLeftBars, StG_FractalsRightBars);
    double sell_signal_price = GetFractalSignal(-1, StG_Timeframe, StG_SearchPeriod, StG_FractalsLeftBars, StG_FractalsRightBars);

    //--- 处理买入挂单
    if(buy_signal_price > 0)
    {
        double stop_price = NormalizeDouble(buy_signal_price + StG_BuyStop_Offset_Points * m_point, m_digits);
        double sl = NormalizeDouble(stop_price - StG_StopLoss_Points * m_point, m_digits);
        double tp = NormalizeDouble(stop_price + StG_TakeProfit_Points * m_point, m_digits);
        datetime expiration = TimeCurrent() + (StG_Pending_Expiration_Hours * 3600);

        if(stop_price > SymbolInfoDouble(m_symbol, SYMBOL_ASK))
        {
            // 临时设置策略G的魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber + 7);
            m_trade.BuyStop(StartLots, stop_price, m_symbol, sl, tp, ORDER_TIME_SPECIFIED, expiration, TradeComment + "_G");
            // 恢复基础魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber);
        }
    }

    //--- 处理卖出挂单
    if(sell_signal_price > 0)
    {
        double stop_price = NormalizeDouble(sell_signal_price + StG_SellStop_Offset_Points * m_point, m_digits);
        double sl = NormalizeDouble(stop_price + StG_StopLoss_Points * m_point, m_digits);
        double tp = NormalizeDouble(stop_price - StG_TakeProfit_Points * m_point, m_digits);
        datetime expiration = TimeCurrent() + (StG_Pending_Expiration_Hours * 3600);

        if(stop_price < SymbolInfoDouble(m_symbol, SYMBOL_BID))
        {
            // 临时设置策略G的魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber + 7);
            m_trade.SellStop(StartLots, stop_price, m_symbol, sl, tp, ORDER_TIME_SPECIFIED, expiration, TradeComment + "_G");
            // 恢复基础魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber);
        }
    }
}

//+------------------------------------------------------------------+
//| 策略 H 执行逻辑                                                  |
//+------------------------------------------------------------------+
void ExecuteStrategyH()
{
    //--- 如果挂单超出限制，删除最不可能成交的挂单
    if(DeleteOldest)
    {
        ManageExceededPendingOrders(BaseMagicNumber + 8, StH_Max_Pending_Orders, StH_Max_Pending_Orders);
    }
    
    //--- 检查是否允许交易
    if(!IsTradingAllowed()) return;
    
    //--- 检查是否有新的K线生成，避免在同一根K线上重复操作
    MqlRates rates[];
    if(CopyRates(m_symbol, StH_Timeframe, 0, 1, rates) < 1) return;
    if(rates[0].time == StH_LastSignalBarTime) return;
    StH_LastSignalBarTime = rates[0].time;

    //--- 检查当前策略的挂单数量
    int pending_orders_count = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderGetTicket(i) > 0)
        {
            if(OrderGetInteger(ORDER_MAGIC) == BaseMagicNumber + 8 && OrderGetString(ORDER_SYMBOL) == m_symbol)
            {
                if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP || OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP)
                {
                    pending_orders_count++;
                }
            }
        }
    }

    if(pending_orders_count >= StH_Max_Pending_Orders)
    {
        return; // 已达到最大挂单数
    }

    //--- 获取信号
    double buy_signal_price = GetFractalSignal(1, StH_Timeframe, StH_SearchPeriod, StH_FractalsLeftBars, StH_FractalsRightBars);
    double sell_signal_price = GetFractalSignal(-1, StH_Timeframe, StH_SearchPeriod, StH_FractalsLeftBars, StH_FractalsRightBars);

    //--- 处理买入挂单
    if(buy_signal_price > 0)
    {
        double stop_price = NormalizeDouble(buy_signal_price + StH_BuyStop_Offset_Points * m_point, m_digits);
        double sl = NormalizeDouble(stop_price - StH_StopLoss_Points * m_point, m_digits);
        double tp = NormalizeDouble(stop_price + StH_TakeProfit_Points * m_point, m_digits);
        datetime expiration = TimeCurrent() + (StH_Pending_Expiration_Hours * 3600);

        if(stop_price > SymbolInfoDouble(m_symbol, SYMBOL_ASK))
        {
            // 临时设置策略H的魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber + 8);
            m_trade.BuyStop(StartLots, stop_price, m_symbol, sl, tp, ORDER_TIME_SPECIFIED, expiration, TradeComment + "_H");
            // 恢复基础魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber);
        }
    }

    //--- 处理卖出挂单
    if(sell_signal_price > 0)
    {
        double stop_price = NormalizeDouble(sell_signal_price + StH_SellStop_Offset_Points * m_point, m_digits);
        double sl = NormalizeDouble(stop_price + StH_StopLoss_Points * m_point, m_digits);
        double tp = NormalizeDouble(stop_price - StH_TakeProfit_Points * m_point, m_digits);
        datetime expiration = TimeCurrent() + (StH_Pending_Expiration_Hours * 3600);

        if(stop_price < SymbolInfoDouble(m_symbol, SYMBOL_BID))
        {
            // 临时设置策略H的魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber + 8);
            m_trade.SellStop(StartLots, stop_price, m_symbol, sl, tp, ORDER_TIME_SPECIFIED, expiration, TradeComment + "_H");
            // 恢复基础魔术数
            m_trade.SetExpertMagicNumber(BaseMagicNumber);
        }
    }
}
//+------------------------------------------------------------------+ 